package br.ucb.JPA;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

public abstract class GenericDAO<T> implements Serializable {  
	private static final long serialVersionUID = 1L;
	
	private EntityManager em;
	
	@SuppressWarnings("rawtypes")
	private Class classe;
	
	@SuppressWarnings("rawtypes")
	public GenericDAO() {
		this.classe = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		this.em = ConnectionFactory.getEntityManager();
	}

	public boolean incluir(T objeto) {
		if (!this.em.getTransaction().isActive())
			this.em.getTransaction().begin();
		
		this.em.persist(objeto);
		this.em.flush();
		
		try {
			this.em.getTransaction().commit();
			return true;
		} catch (Exception e) {
			this.em.getTransaction().rollback();
			return false;
		}
	}

	public boolean alterar(T objeto) {
		if (!this.em.getTransaction().isActive())
			this.em.getTransaction().begin();
		
		this.em.merge(objeto);
		this.em.flush();
		
		try {
			this.em.getTransaction().commit();
			return true;
		} catch (Exception e) {
			this.em.getTransaction().rollback();
			return false;
		}
	}
	
	public boolean excluir(T objeto) {
		if (!this.em.getTransaction().isActive())
			this.em.getTransaction().begin();

		if (!this.em.contains(objeto)) {
		    objeto = em.merge(objeto);
			this.em.getTransaction().commit();
			
			if (!this.em.getTransaction().isActive())
				this.em.getTransaction().begin();
		}
		
		this.em.remove(objeto);
		this.em.flush();
		
		try {
			this.em.getTransaction().commit();
			return true;
		} catch (Exception e) {
			this.em.getTransaction().rollback();
			return false;
		}
	}

	@SuppressWarnings("unchecked")
	public T consultar(Long id) {
		return (T) this.em.find(this.classe, id);
	}

	@SuppressWarnings("unchecked")
	public T consultaGenerica(String sql) {
		Query q = this.em.createQuery(sql);
		return (T)q.getSingleResult();
	}

	@SuppressWarnings("unchecked")
	public List<T> consultaConjunto(String sql) {
		Query q = this.em.createNativeQuery(sql, this.classe);
		return q.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<T> listar() {
		Query q = this.em.createQuery("SELECT e FROM " + this.classe.getSimpleName() +" e");
		return q.getResultList();
	}
	
	public EntityManager getEm() {
		return em;
	}
}
